
const lodash = require('lodash')
import { pageFns } from '../utils/pageHelper'
import { AccountDao } from '@/dao/accountDao'

// const SELECTORS = {
//     LOGINBTNS: [],
//     USERNAMES: [],
//     NEXTSTEPS: [],
//     PASSWORDS: [],
//     COMFIRMBTNS: [],
//     UNLOGINFLAGS: "",
// }
// [[],"xxx",[]],多维模式
async function multilMetricSels(page, selectors) {
    let hasArray = false
    for (let btns of selectors) {
        if (lodash.isArray(btns)) {
            hasArray = true
            break
        }
    }
    if (hasArray) {
        for (let btns of selectors) {
            if (!lodash.isArray(btns)) {
                btns = [btns]
            }
            let res = await pageFns.deepRetry(btns, page, async (selector, page) => {
                console.log("hasArray", selector)
                await page.waitForSelector(selector)
                await page.click(selector)
            }, { page: page, timeout: 10 * 1000 })
            if (res.err) {
                return res
            }
        }
    } else {
        let res = await pageFns.deepRetry(selectors, page, async (selector, page) => {
            await page.waitForSelector(selector)
            await page.click(selector)
        }, { page: page, timeout: 10 * 1000 })
        if (res.err) {
            return res
        }
    }
    return { data: true }
}

async function login(page, selectors, account) {
    // 如果当前页面路径与loginUrl，说明是登录页了
    if (!page.url().includes(account.loginUrl)) {
        let res = await pageFns.tryCatch(page, async (obj, page) => {
            await page.goto(account.loginUrl, { waitUntil: 'networkidle0' })
        }, { page: page, timeout: 60 * 1000 })
        if (res.err) {
            return res
        }
    }
    // 是否需要点击一下登录按钮,支持多维
    if (!lodash.isEmpty(selectors.LOGINBTNS)) {
        let res = await multilMetricSels(page, selectors.LOGINBTNS)
        if (res.err) {
            return res
        }
    }
    // 开始输入帐号
    if (!lodash.isEmpty(selectors.USERNAMES)) {
        let res = await pageFns.deepRetry(selectors.USERNAMES, page, async (selector, page) => {
            await page.waitForSelector(selector);
            await page.type(selector, account.account);
        }, { page: page, timeout: 200 * 1000 })
        if (res.err) {
            return res
        }
    }
    // 是否要点击一下才能输入密码
    if (!lodash.isEmpty(selectors.NEXTSTEPS)) {
        let res = await pageFns.deepRetry(selectors.NEXTSTEPS, page, async (selector, page) => {
            await page.waitForSelector(selector);
            await page.click(selector);
        }, { page: page, timeout: 10 * 1000 })
        if (res.err) {
            return res
        }
    }
    // 输入密码
    if (!lodash.isEmpty(selectors.PASSWORDS) && !lodash.isEmpty(account.password)) {
        let res = await pageFns.deepRetry(selectors.PASSWORDS, page, async (selector, page) => {
            await page.waitForSelector(selector);
            await page.type(selector, account.password);
        }, { page: page, timeout: 5 * 1000, wait: 5 * 1000 })
        if (res.err) {
            return res
        }
    } else {
        //没有密码默认：发送验证码
        await pageFns.delay(60 * 1000)
    }
    // 点击用户协议
    if (!lodash.isEmpty(selectors.AGREEMENTBTNS)) {
        let res = await pageFns.deepRetry(selectors.AGREEMENTBTNS, page, async (selector, page) => {
            console.log("AGREEMENT", selector)
            if (selector == "--") {
                return "占位无报错"
            }
            await page.waitForSelector(selector);
            await page.click(selector);
        }, { page: page, timeout: 3 * 1000, wait: 5 * 1000 })
        if (res.err) {
            console.log("AGREEMENT test", res)
            return res
        }
    }
    // 点击确认按钮
    console.log("COMFIRMBTNS test")
    if (!lodash.isEmpty(selectors.COMFIRMBTNS)) {
        let res = await pageFns.deepRetry(selectors.COMFIRMBTNS, page, async (selector, page, setting) => {
            await page.waitForSelector(selector)
            await page.click(selector)
            await page.waitForFunction((selector) => {
                return !document.querySelector(selector)
            }, { timeout: setting.timeout }, selector);
        }, { page: page, wait: 10 * 1000, timeout: 10 * 1000 })
        if (res.err) {
            return res
        }
    }
    return { err: null, data: true }
}
// 检查是否登录，并定向到目标页
async function checked(page, selectors, account, task, isFirst) {
    if (isFirst) {
        let result = await pageFns.tryCatch(page, async (obj, page) => {
            if (existLoginState(account)) {
                await page.goto(account.loginUrl, { waitUntil: 'networkidle0' })
                await restoreLoginState(page, account)
                await page.goto(task.targetUrl, { waitUntil: 'networkidle0' })
            } else {
                await page.goto(task.targetUrl, { waitUntil: 'networkidle0' })
            }
        }, { page: page, timeout: 60 * 1000, wait: 5 * 1000 })
        if (result.err) {
            console.log("checked", isFirst, result)
            return result
        }
    } else {
        let url = page.url()
        if (!url.includes(task.targetUrl) && !url.includes(account.loginUrl)) {
            let result = await pageFns.tryCatch(page, async (obj, page) => {
                await page.goto(task.targetUrl, { waitUntil: 'networkidle0' })
            }, { page: page, timeout: 60 * 1000, wait: 5 * 1000 })
            if (result.err) {
                return result
            }
        }
    }
    // 检测是否是登录状态
    let res = await checkHadLogin(page, selectors)
    console.log("checkFlag", res, isFirst)
    if (res.err) {
        return { err: "未登录" }
    }
    if (!isFirst) {
        await saveLoginState(page, account)
        await pageFns.delay(60 * 1000)
        await saveLoginState(page, account)
    }
    return res
}

async function checkHadLogin(page, selectors) {
    let lastSelector = lodash.last(selectors.UNLOGINFLAGS)
    let res = await pageFns.deepRetry(selectors.UNLOGINFLAGS, page, async (selector, page, settting) => {
        let isExist = await pageFns.isSelExist(page, selector)
        if (lastSelector == selector) {
            return isExist
        }
        if (!isExist) {
            throw new Error("未登录")
        }
        return true
    }, { page: page, timeout: 10 * 100 })
    if (res.err) {
        return res
    }
    return { err: null, data: !res.data }
}

async function checkLogin(page, task, selectors) {
    let account = await AccountDao.fetchByID(task.accountId)
    if (!account) {
        return { err: "找不到帐号" }
    }
    // 检查登录状态
    let res = await checked(page, selectors, account, task, true)
    if (res.err) {
        return res
    }
    // 未登录时，进行登录
    if (!selectors) {
        selectors = JSON.parse(account.selectors)
    }
    console.log("first checked", res)
    if (!res.data) {
        res = await login(page, selectors, account)
        console.log("login", res)
        if (res.err) {
            return res
        }
        res = await checked(page, selectors, account, task, false)
        console.log("second login", res)
        if (res.err || !res.data) {
            return { err: "登录失败", data: "" }
        }
    }
    return { err: null, data: account }
}

function existLoginState(account) {
    if (account.cookie || account.storage) {
        return true
    }
    return false
}

async function restoreLoginState(page, account) {
    if (account.cookie) {
        const cookies = JSON.parse(account.cookie);
        await page.setCookie(...cookies);
    }
    if (account.storage) {
        const localStorageObj = JSON.parse(account.storage);
        await page.evaluate((localStorageObj) => {
            for (let key in localStorageObj) {
                window.localStorage.setItem(key, localStorageObj[key]);
            }
        }, localStorageObj);
    }
}

async function saveLoginState(page, account) {
    const cookies = await page.cookies();
    const localStorageString = await page.evaluate(() => {
        return JSON.stringify(window.localStorage, null, 2);
    });
    account.cookie = JSON.stringify(cookies)
    account.storage = localStorageString
    return await AccountDao.save(account)
}


export { checkLogin, checkHadLogin, login }
